#include <windows.h>
#include <iostream>
#include <stdio.h>
using namespace std;

static LPCTSTR g_szMutexName = TEXT("w2kdg.ProcTerm.mutex.Suicide");

void StartClone()
{
    TCHAR szFilename[MAX_PATH];
    GetModuleFileName(NULL, szFilename, MAX_PATH);

    TCHAR szCmdLine[MAX_PATH];
#ifdef UNICODE
    swprintf_s(szCmdLine, MAX_PATH, L"\"%ls\" child", szFilename);
#else
    sprintf_s(szCmdLine, MAX_PATH, "\"%s\" child", szFilename);
#endif

    STARTUPINFO si;
    ZeroMemory(reinterpret_cast<void*>(&si), sizeof(si));
    si.cb = sizeof(si);

    PROCESS_INFORMATION pi;

    BOOL bCreateOK = CreateProcess(
        szFilename,
        szCmdLine,
        NULL,
        NULL,
        FALSE,
        0,
        NULL,
        NULL,
        &si,
        &pi);

    if (!bCreateOK) {
        cerr << "Failed to create process. Error: " << GetLastError() << endl;
        return;
    }

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

void Parent()
{
    HANDLE hMutexSuicide = CreateMutex(
        NULL,
        TRUE,
        g_szMutexName);

    if (hMutexSuicide == NULL) {
        cerr << "Failed to create mutex. Error: " << GetLastError() << endl;
        return;
    }

    cout << "Creating the child process." << endl;
    StartClone();
    Sleep(5000);
    cout << "Telling the child process to quit." << endl;
    ReleaseMutex(hMutexSuicide);
    CloseHandle(hMutexSuicide);
}

void Child()
{
    HANDLE hMutexSuicide = OpenMutex(
        SYNCHRONIZE,
        FALSE,
        g_szMutexName);

    if (hMutexSuicide == NULL) {
        cerr << "Failed to open mutex. Error: " << GetLastError() << endl;
        return;
    }

    cout << "Child waiting for suicide instructions." << endl;
    WaitForSingleObject(hMutexSuicide, INFINITE);
    cout << "Child quitting." << endl;
    CloseHandle(hMutexSuicide);
    Sleep(5000);
}

int main(int argc, char* argv[])
{
    if (argc > 1 && strcmp(argv[1], "child") == 0)
    {
        Child();
    }
    else
    {
        Parent();
    }
    return 0;
}